package org.stormphoenix.bbsfamily.config

import com.github.dozermapper.core.Mapper
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.AuthenticationException
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.util.DigestUtils
import org.stormphoenix.bbsfamily.dao.UserMapper
import org.stormphoenix.bbsfamily.dao.UserRepository
import org.stormphoenix.bbsfamily.entity.RoleDO
import org.stormphoenix.bbsfamily.entity.UserDO
import org.stormphoenix.bbsfamily.entity.dto.UserDTO
import org.stormphoenix.bbsfamily.utils.JwtTokenUtil
import java.sql.Timestamp

@Service("userService")
@Transactional
class UserService : UserDetailsService {
    @Autowired
    lateinit var userRepository: UserRepository

    @Autowired
    lateinit var userMapper: UserMapper

    /**
     * DTO、DO 映射工具
     */
    @Autowired
    @Qualifier("dozerMapper")
    lateinit var mapper: Mapper

    @Autowired
    lateinit var passwordEncoder: PasswordEncoder

    @Autowired
    lateinit var jwtTokenUtil: JwtTokenUtil

    override fun loadUserByUsername(username: String?): UserDetails? {
        return username?.let {
            val user = userMapper.findUserByUsername(username)
            user?.let { UserDetailsDO(user) } ?: null
        } ?: null
    }

    fun login(username: String, password: String): String? {
        var token: String? = null
        //密码需要客户端加密后传递
        try {
            val userDetails = loadUserByUsername(username)

            var matched = userDetails?.let {
                passwordEncoder.matches(password, userDetails.password)
            } ?: false
            if (!matched) {
                throw BadCredentialsException("用户名或密码错误")
            }

            val authentication = UsernamePasswordAuthenticationToken(userDetails, null, userDetails!!.getAuthorities())
            SecurityContextHolder.getContext().authentication = authentication
            token = jwtTokenUtil.generateToken(userDetails)
        } catch (e: AuthenticationException) {
            LOGGER.warn("登录异常:{}", e.message)
        }
        return token
    }

    fun register(userDTO: UserDTO): Int {
        loadUserByUsername(userDTO.username)?.let {
            return USER_EXIST
        }

        val user = mapper.map(userDTO, UserDO::class.java)
        user.password = DigestUtils.md5DigestAsHex(user.password.toByteArray())
        user.enabled = true
        user.roles = DEFAULT_ROLES
        // 注册时间使用数据库默认值
        user.regTime = Timestamp(System.currentTimeMillis())
        userRepository.save(user)
//        TODO 注意检查是否插入成功
        return REGISTER_SUCCESS
    }

    companion object {
        val REGISTER_SUCCESS: Int = 1
        val USER_EXIST: Int = 2
        val DEFAULT_ROLES = mutableListOf<RoleDO>(RoleDO(2, "USER"))
        private val LOGGER = LoggerFactory.getLogger(UserService::class.java)
    }
}
